package com.danbay.cloud.account.service;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.danbay.cloud.account.client.SmsServiceClient;
import com.danbay.cloud.account.config.AccountProperties;
import com.danbay.cloud.account.dto.*;
import com.danbay.cloud.account.entity.*;
import com.danbay.cloud.account.mapper.*;
import com.danbay.cloud.account.service.api.IEnterpriseService;
import com.danbay.cloud.base.constants.Roles;
import com.danbay.cloud.common.api.dto.sms.EmployeeRegNoticeDto;
import com.danbay.framework.db.pagination.PageParam;
import com.danbay.framework.db.pagination.PageQuery;
import com.danbay.framework.db.pagination.PageResult;
import com.danbay.framework.db.pagination.PagingHelper;
import com.danbay.framework.exception.BusinessException;
import com.danbay.framework.utils.BeanUtils;
import com.danbay.framework.utils.BeanValidator;
import com.danbay.framework.utils.DateUtils;
import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * @author SJG
 *         2017/12/26.
 */
@Service
public class EnterpriseService implements IEnterpriseService {

    @Autowired
    private EnterpriseMapper enterpriseMapper;

    @Autowired
    private AccountMapper accountMapper;
    @Autowired
    private AccountRoleMapper accountRoleMapper;
    @Autowired
    private AccountPermissionMapper accountPermissionMapper;
    @Autowired
    private AccountGroupMapper accountGroupMapper;
    @Autowired
    private PermissionGroupMapper permissionGroupMapper;

    @Autowired
    private AccountProperties accountProperties;

    @Autowired
    private ContractService contractService;
    @Autowired
    private AccountService accountService;
    @Autowired
    private PermissionService permissionService;
    @Autowired
    private SmsServiceClient smsServiceClient;

    /**
     * 分页查找企业信息
     *
     * @param param 分页查询查询参数
     * @return 返回分页的企业信息列表
     */
    @Override
    public PageResult<EnterpriseInfoDto> findByPage(PageParam<EnterpriseInfoDto> param) {
        return PagingHelper.pageQuery(param, EnterpriseInfoDto.class, Enterprise.class,
                (PageQuery<Enterprise, Enterprise>) (page, param1) -> enterpriseMapper.findEnterprises(page, param1));
    }

    /**
     * 取企业信息
     *
     * @param eid 企业id
     * @return 企业信息
     * @throws BusinessException 业务异常
     */
    @Override
    public EnterpriseInfoDto get(Integer eid) throws BusinessException {
        if (eid == null) {
            throw new BusinessException("企业id不能为空");
        }
        return BeanUtils.convert(enterpriseMapper.selectById(eid), EnterpriseInfoDto.class);
    }

    /**
     * 添加企业信息
     *
     * @param info 企业信息
     * @throws BusinessException 业务异常
     */
    @Override
    public Integer add(AddEnterpriseDto info) throws BusinessException {
        BeanValidator.valid(info);

        Enterprise enterprise = Enterprise.builder().
                name(info.getName())
                .address("")
                .regionId(0)
                .parentId(0)
                .trial(info.getTrial())
                .freeze(false)
                .del(false)
                .addTime(DateTime.now().toDate())
                .build();
        enterpriseMapper.insert(enterprise);
        return enterprise.getId();
    }

    /**
     * 添加企业账户
     *
     * @param accountDto 企业账户信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addEnterpriseAccount(EnterpriseAccountDto accountDto) throws BusinessException {
        //试用账户合同号使用自动生成
        if (accountDto.getTrial()) {
            accountDto.setContractNum("TEST" + DateUtils.now(DateUtils.YMDHMS2));
        }

        //参数校验
        BeanValidator.valid(accountDto);
        //1.添加企业信息
        //1.1.添加账户组
        AccountGroup accountGroup = AccountGroup.builder().groupName(accountDto.getEnterpriseName()).parentId(0).del(false).build();
        accountGroupMapper.insert(accountGroup);
        //1.2.添加企业信息
        Integer enterpriseId = add(AddEnterpriseDto.builder().name(accountDto.getEnterpriseName()).trial(accountDto.getTrial()).build());
        //2.添加合同
        contractService.addContract(accountDto.getContractNum(), enterpriseId);
        //3.添加账户信息
        accountService.addAccount(AccountDto.builder()
                .userName(accountDto.getUserName())
                .phoneNum(accountDto.getPhoneNum())
                .accountGroup(accountGroup.getId())
                .build());
        //4.设置账户角色
        accountRoleMapper.insert(AccountRole.builder().userName(accountDto.getUserName()).roleName(Roles.ENTERPRISE.roleName()).build());
        //5.绑定账户和账户组
        bindAccount(enterpriseId, accountGroup.getId(), accountDto.getUserName());
        //todo 先由后台添加默认的企业账户权限,后续平台管理员可以选择企业账户权限时再由前端设置权限
        List<AccountPermissionDto.Permission> permissions = new ArrayList<>();
        permissions.add(new AccountPermissionDto.Permission(5, ""));
        permissionService.assignAccountPermission(AccountPermissionDto.builder()
                .accountGroupId(accountGroup.getId()).userName(accountDto.getUserName())
                .permissions(permissions)
                .build());
        //6.前端再调用发送密码
    }

    /**
     * 取企业账户信息
     *
     * @param eid 企业id
     * @return 企业账户信息
     */
    @Override
    public EnterpriseAccountInfoDto getAccountInfo(Integer eid) {
        Enterprise enterprise = enterpriseMapper.selectById(eid);
        Account account = accountMapper.selectById(enterprise.getBindAccount());
        return EnterpriseAccountInfoDto.builder()
                .enterpriseName(enterprise.getName())
                .trial(enterprise.getTrial())
                .freeze(enterprise.getFreeze())
                .accountGroupId(enterprise.getAccountGroupId())
                .phoneNum(account.getPhoneNum())
                .userName(enterprise.getBindAccount())
                .build();
    }

    /**
     * 修改企业名
     *
     * @param eid  企业id
     * @param name 企业名
     * @throws BusinessException 业务异常
     */
    @Override
    public void edit(Integer eid, String name) throws BusinessException {
        enterpriseMapper.updateById(Enterprise.builder().id(eid).name(name).build());
    }

    /**
     * 删除企业信息
     * 只有试用账户才能被删除，确认相关提示并删除后，与该账号关联的设备
     * 信息和房源信息同样被取消关联和删除。
     *
     * @param eid 企业id
     * @throws BusinessException 业务异常
     */
    @Override
    public void delete(Integer eid) throws BusinessException {
        Enterprise enterprise = enterpriseMapper.selectById(eid);
        if (!enterprise.getTrial()) {
            throw new BusinessException("正式企业账户不能被删除");
        }
        //删除企业信息
        enterpriseMapper.deleteById(eid);
        String userName = enterprise.getBindAccount();
        if (StringUtils.isBlank(userName)) {
            return;
        }
        //删除账户
        accountMapper.deleteById(userName);
        //删除账户组
        accountGroupMapper.deleteById(enterprise.getAccountGroupId());
        //删除账户角色
        accountRoleMapper.delete(new EntityWrapper<>(AccountRole.builder().userName(userName).build()));
        //删除账户权限
        accountPermissionMapper.delete(new EntityWrapper<>(AccountPermission.builder().userName(userName).build()));
        //删除与房源关联
        //todo
    }

    /**
     * 绑定账户组和账户
     *
     * @param eid       企业id
     * @param groupId   账户组id
     * @param accountId 账户id
     * @throws BusinessException 业务异常
     */
    @Override
    public void bindAccount(Integer eid, Integer groupId, String accountId) throws BusinessException {
        Enterprise enterprise = enterpriseMapper.selectById(eid);
        AccountGroup accountGroup = accountGroupMapper.selectById(groupId);
        Account account = accountMapper.selectById(accountId);
        if (enterprise == null || accountGroup == null || account == null) {
            throw new BusinessException("企业、账户组或账户不存在");
        }
        enterpriseMapper.updateById(Enterprise.builder().id(eid).accountGroupId(groupId).bindAccount(accountId).build());
    }

    /**
     * 更改企业关联的账户
     * 相当于创建新的账户绑定到该企业
     *
     * @param eid      企业信息id
     * @param userName 用户名
     * @param phoneNum 手机号
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changeAccount(Integer eid, String userName, String phoneNum) throws BusinessException {
        Enterprise enterprise = enterpriseMapper.selectById(eid);
        if (enterprise == null) {
            throw new BusinessException("该企业不存在");
        }
        accountService.addAccount(AccountDto.builder()
                .userName(userName)
                .phoneNum(phoneNum)
                .accountGroup(enterprise.getAccountGroupId())
                .build());

        //4.设置账户角色
        accountRoleMapper.insert(AccountRole.builder().userName(userName).roleName(Roles.ENTERPRISE.roleName()).build());
        //5.绑定账户和账户组
        bindAccount(eid, enterprise.getAccountGroupId(), userName);
        //todo 先由后台添加默认的企业账户权限,后续平台管理员可以选择企业账户权限时再由前端设置权限
        List<AccountPermissionDto.Permission> permissions = new ArrayList<>();
        permissions.add(new AccountPermissionDto.Permission(3, ""));
        permissionService.assignAccountPermission(AccountPermissionDto.builder()
                .accountGroupId(enterprise.getAccountGroupId()).userName(userName)
                .permissions(permissions)
                .build());
        //更新绑定账户
        enterpriseMapper.updateById(Enterprise.builder().id(eid).bindAccount(userName).build());
        //老账户置为已冻结
        accountService.freeze(enterprise.getBindAccount());
    }

    /**
     * 升级试用企业到正式企业
     * 1.把企业信息标识为正式
     * 2.删除试用合同号
     * 3.补充合同号（前端调用新增合同号）
     *
     * @param eid 企业id
     * @throws BusinessException 业务异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void upgrade(Integer eid) throws BusinessException {
        enterpriseMapper.updateById(Enterprise.builder().id(eid).trial(false).build());
        contractService.deleteByEid(eid);
    }

    /**
     * 冻结企业
     * 1.冻结企业,2.将企业绑定账户置为不可用
     *
     * @param eid 企业id
     * @throws BusinessException 业务异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void freeze(Integer eid) throws BusinessException {
        Enterprise enterprise = enterpriseMapper.selectById(eid);
        if (enterprise == null) {
            throw new BusinessException("该企业不存在");
        }
        if (enterprise.getBindAccount() == null) {
            throw new BusinessException("该企业未绑定账户");
        }
        enterpriseMapper.updateById(Enterprise.builder().id(eid).freeze(true).freezeTime(DateTime.now().toDate()).build());
        accountService.freeze(enterprise.getBindAccount());
    }

    /**
     * 解冻企业
     * 1.解冻企业,2.将企业绑定账户置为可用
     *
     * @param eid 企业id
     * @throws BusinessException 业务异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void unfreeze(Integer eid) throws BusinessException {
        Enterprise enterprise = enterpriseMapper.selectById(eid);
        if (enterprise == null) {
            throw new BusinessException("该企业不存在");
        }
        if (enterprise.getBindAccount() == null) {
            throw new BusinessException("该企业未绑定账户");
        }
        enterpriseMapper.updateById(Enterprise.builder().id(eid).freeze(false).freezeTime(DateTime.now().toDate()).build());
        accountService.unfreeze(enterprise.getBindAccount());
    }

    /**
     * 企业账户注册成功后,发送注册短信
     *
     * @param mobile 企业账户电话
     * @param name   企业名
     */
    @Override
    public void sendRegMessage(String mobile, String name) throws BusinessException {
        smsServiceClient.sendRegisterNotice(
                EmployeeRegNoticeDto.builder()
                        .name(name)
                        .tel(mobile)
                        .pwd(accountProperties.getDefaultPassword())
                        .build());
    }

    /**
     * 修改绑定企业账户名和电话，发送账户绑定短信
     *
     * @param mobile 企业账户电话
     * @param name   企业名
     */
    @Override
    public void sendBindMessage(String mobile, String name) throws BusinessException {
        smsServiceClient.sendBindAccountNotice(
                EmployeeRegNoticeDto.builder()
                        .name(name)
                        .tel(mobile)
                        .pwd(accountProperties.getDefaultPassword())
                        .build());
    }

    /**
     * 企业账户变更时，发送账户变更短信
     *
     * @param mobile 企业账户电话
     * @param name   企业名
     */
    @Override
    public void sendAccountChangeMessage(String mobile, String name) throws BusinessException {
        smsServiceClient.sendAccountChangeNotice(
                EmployeeRegNoticeDto.builder()
                        .name(name)
                        .tel(mobile)
                        .pwd(accountProperties.getDefaultPassword())
                        .build());
    }
}
